﻿using System;
using System.Collections.Generic;
using System.Text;
using Quicklight.Web.Injection;

namespace Quicklight.Web {
   
   /// <summary>
   /// The Container is a named logical representation of the UI component that contains and shows an IViewable object.
   /// The namespace and name of the container specify to the IViewable object where it should render itself.
   /// The Container also has a dictionary named Parameters that contain name value pairs passed to the IViewable object.
   /// </summary>
   public class Container {
      private string name;
      private string nameSpace;
      private IViewable view;
      private Type viewType;
      private string viewName;
      private Dictionary<string, object> parameters;

      /// <summary>
      /// Constructs a Container with the specified name and namespace. Together the name and namespace references the UI component within which the specified IViewable object should render itself.
      /// </summary>
      /// <param name="name">The name of the Container</param>
      /// <param name="nameSpace">The namespace of the Container</param>
      public Container(string name, string nameSpace) {
         this.name = name;
         this.nameSpace = nameSpace;
         this.parameters = new Dictionary<string, object>();
      }

      /// <summary>
      /// Name of the Container. The Name together with the NameSpace of the Container refer to the full name of the UI component within which the IViewable object will render itself
      /// </summary>
      public string Name {
         get {
            return name;
         }
         set {
            name = value;
         }
      }

      /// <summary>
      /// NameSpace of the Container. The NameSpace together with the Name of the Container refer to the full name of the UI component within which the IViewable object will render itself
      /// </summary>
      public string NameSpace {
         get {
            return nameSpace;
         }
         set {
            nameSpace = value;
         }
      }

      /// <summary>
      /// The FullName of the Container refers to the full name of the UI component within which the IViewable object will render itself
      /// </summary>
      public string FullName {
         get {
            if (String.IsNullOrEmpty(nameSpace))
               return name;
            else
               return nameSpace + "." + name;
         }
      }

      /// <summary>
      /// Dictionary of parameters that is passed to the IViewable object to use in rendering itself
      /// </summary>
      public Dictionary<string, object> Parameters {
         get { return parameters; }
      }

      /// <summary>
      /// Resolve the IViewable object, if only its type was specified and then call the Render method of the IViewable object passing in this container as parameter
      /// </summary>
      public void Render() {
         if ((view == null) && (viewType != null))
            view = (IViewable)ObjectManager.Instance.Resolve(viewType, viewName);
         
         if (view != null)
            view.Render(this);
      }

      /// <summary>
      /// Load the specified IViewable into the container but do not render it
      /// </summary>
      /// <param name="view">The IViewable instance to store for later rendering</param>
      public void Load(IViewable view) {
         this.view = view;
         this.viewType = view.GetType();
         this.viewName = "";
      }

      /// <summary>
      /// Store the specified IViewable type. Will be used to resolve the IViewable instance from the ObjectManager when Render method is called
      /// To register a view for resolving by this method use any of the following methods
      ///  - ObjectManager.Instance.RegisterType<TViewable>();
      ///  - ObjectManager.Instance.RegisterType<TViewable, TTo>();
      ///  - ObjectManager.Instance.RegisterType(typeof(TViewable));
      ///  - ObjectManager.Instance.RegisterType(typeof(TViewable), typeof(to));
      ///  - ObjectManager.Instance.RegisterInstance<TInterface>(view);
      ///  - ObjectManager.Instance.RegisterInstance(typeof(TViewable), view);
      /// </summary>
      /// <typeparam name="TViewable">IViewable type that will be rendered on calling the Render method</typeparam>
      public void Load<TViewable>() where TViewable : IViewable {
         this.view = null;
         this.viewType = typeof(TViewable);
         this.viewName = "";
      }
      
      /// <summary>
      /// Store the specified IViewable type and viewname. Will be used to resolve the IViewable instance from the ObjectManager when Render method is called
      ///  - ObjectManager.Instance.RegisterType<TViewable>(viewName);
      ///  - ObjectManager.Instance.RegisterType<TViewable, TTo>(viewName);
      ///  - ObjectManager.Instance.RegisterType(typeof(TViewable), viewName);
      ///  - ObjectManager.Instance.RegisterType(typeof(TViewable), typeof(to), viewName);
      ///  - ObjectManager.Instance.RegisterInstance<TInterface>(viewName, view);
      ///  - ObjectManager.Instance.RegisterInstance(typeof(TViewable), viewName, view);
      /// </summary>
      /// <typeparam name="TViewable">IViewable type to use when resolving the IViewable instance</typeparam>
      /// <param name="viewName">View name to use when resolving the IViewable instance</param>
      public void Load<TViewable>(string viewName) where TViewable : IViewable {
         this.view = null;
         this.viewType = typeof(TViewable);
         this.viewName = viewName;
      }

      /// <summary>
      /// Store and render the IViewable instance
      /// </summary>
      /// <param name="view">IViewable instance to render</param>
      public void Show(IViewable view) {
         this.view = view;
         this.viewType = view.GetType();
         this.viewName = "";

         Render();
      }

      /// <summary>
      /// Resolve and render the IViewable type
      /// To register a view for resolving by this method use any of the following methods
      ///  - ObjectManager.Instance.RegisterType<TViewable>();
      ///  - ObjectManager.Instance.RegisterType<TViewable, TTo>();
      ///  - ObjectManager.Instance.RegisterType(typeof(TViewable));
      ///  - ObjectManager.Instance.RegisterType(typeof(TViewable), typeof(to));
      ///  - ObjectManager.Instance.RegisterInstance<TInterface>(view);
      ///  - ObjectManager.Instance.RegisterInstance(typeof(TViewable), view);
      /// </summary>
      /// <typeparam name="TViewable">The IViewable type to resolve and render</typeparam>
      public void Show<TViewable>() where TViewable : IViewable {
         this.view = null;
         this.viewType = typeof(TViewable);
         this.viewName = "";
         
         Render();
      }

      /// <summary>
      /// Resolve and render the IViewable type from the ObjectManager using the type and name specified
      ///  - ObjectManager.Instance.RegisterType<TViewable>(viewName);
      ///  - ObjectManager.Instance.RegisterType<TViewable, TTo>(viewName);
      ///  - ObjectManager.Instance.RegisterType(typeof(TViewable), viewName);
      ///  - ObjectManager.Instance.RegisterType(typeof(TViewable), typeof(to), viewName);
      ///  - ObjectManager.Instance.RegisterInstance<TInterface>(viewName, view);
      ///  - ObjectManager.Instance.RegisterInstance(typeof(TViewable), viewName, view);
      /// </summary>
      /// <typeparam name="TViewable">IViewable type to resolve and render</typeparam>
      /// <param name="viewName">Name of the view to use when resolving</param>
      public void Show<TViewable>(string viewName) where TViewable : IViewable {
         this.view = null;
         this.viewType = typeof(TViewable);
         this.viewName = viewName;
         
         Render();
      }
   }
}
